﻿using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Threading;
using nRoute.Components.Composition;
using nRoute.ViewServices;

namespace nRoute.Samples.OfficerXcel.ViewServices.Controls
{
    [MapViewService(typeof(ITimeoutNotificationViewService),
        InitializationMode = InitializationMode.WhenAvailable,
        Lifetime = ViewServiceLifetime.DiscoveredInstance)]
    public partial class BalloonNotification
        : UserControl, ITimeoutNotificationViewService
    {
        private const string HIDDEN_STATENAME = "HiddenState";
        private const string VISIBLE_STATENAME = "VisibleState";
        private readonly static TimeSpan MIN_TIMEOUT = TimeSpan.FromSeconds(5);
        private readonly static TimeSpan TRANSITION_TIMEOUT = TimeSpan.FromMilliseconds(600);

        private readonly Object _lock = new Object();
        private Queue<BallonMessage> _messages;
        private DispatcherTimer _messageTimer;
        private DispatcherTimer _stateTimer;

        public BalloonNotification()
        {
            InitializeComponent();

            _messages = new Queue<BallonMessage>();
            _messageTimer = new DispatcherTimer();
            _messageTimer.Tick += new EventHandler(MessageTimer_Tick);
            _stateTimer = new DispatcherTimer();
            _stateTimer.Tick += new EventHandler(StateTimer_Tick);
        }

#region ITimeoutNotificationViewService Members

        public void ShowNotification(string message, TimeSpan timeout)
        {
            // basic checks
            if (string.IsNullOrEmpty(message)) throw new ArgumentNullException("message");
            if (timeout < MIN_TIMEOUT)
                throw new ArgumentException("Notification timeout must be atleast 10 seconds.");

            // show or enque message
            lock (_lock)
            {
                // if no items are queued then show the message, else enque
                var _message = new BallonMessage() { Message = message, Timeout = timeout };
                if (_messages.Count == 0 && !_messageTimer.IsEnabled )
                {
                    ShowMessage(_message);
                }
                else
                {
                    _messages.Enqueue(_message);
                }
            }
        }

#endregion

#region Event Handlers

        void MessageTimer_Tick(object sender, EventArgs e)
        {
            _messageTimer.Stop();
            ProcessQueue();
        }

        void StateTimer_Tick(object sender, EventArgs e)
        {
            _stateTimer.Stop();
            VisualStateManager.GoToState(this, HIDDEN_STATENAME, true);
        }

        void CloseBallon_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            if (!_stateTimer.IsEnabled) return;
            
            // we stop the timers and start transitioning
            _messageTimer.Stop();
            _stateTimer.Stop();
            VisualStateManager.GoToState(this, HIDDEN_STATENAME, true);

            // and transiation
            _messageTimer.Interval = TRANSITION_TIMEOUT;
            _messageTimer.Start();
        }

#endregion

#region Helpers

        void ProcessQueue()
        {
            lock (_lock)
            {
                if (_messages.Count == 0) return;
                var _message = _messages.Dequeue();
                ShowMessage(_message);
            }
        }

        void ShowMessage(BallonMessage message)
        {
            this.BallonText.Text = message.Message;
            VisualStateManager.GoToState(this, VISIBLE_STATENAME, true);

            _messageTimer.Interval = message.Timeout;
            _stateTimer.Interval = message.Timeout.Subtract(TRANSITION_TIMEOUT);
            _messageTimer.Start();
            _stateTimer.Start();

        }

#endregion

#region Internal Class

        class BallonMessage
        {
            
            public string Message {get; set; }
            
            public TimeSpan Timeout {get; set; }

        }

#endregion

    }
}
